import { defineStore } from "pinia";
import { isExternal } from "@/utils/validate";
import type {
  LocationQuery,
  RouteLocationNormalized,
  RouteParamsRaw,
  Router,
  RouteRecordName,
} from "vue-router";
import { PageEnum } from "@/enums/pageEnum";

interface TabItem {
  name: RouteRecordName;
  fullPath: string;
  path: string;
  title?: string;
  query?: LocationQuery;
  params?: RouteParamsRaw;
}

interface TabsSate {
  cacheTabList: Set<string>;
  tabList: TabItem[];
  tasMap: Record<string, TabItem>;
  indexRouteName: RouteRecordName;
}

const getHasTabIndex = (fullPath: string, tabList: TabItem[]) => {
  return tabList.findIndex((item) => item.fullPath == fullPath);
};

const isCannotAddRoute = (route: RouteLocationNormalized, router: Router) => {
  const { path, meta, name } = route;
  if (!path || isExternal(path)) return true;
  if (meta?.hideTab) return true;
  if (!router.hasRoute(name!)) return true;
  if (([PageEnum.LOGIN, PageEnum.ERROR_403] as string[]).includes(path)) {
    return true;
  }
  return false;
};

const findTabsIndex = (fullPath: string, tabList: TabItem[]) => {
  return tabList.findIndex((item) => item.fullPath === fullPath);
};

const getComponentName = (route: RouteLocationNormalized) => {
  return route.matched.at(-1)?.components?.default?.name;
};

export const getRouteParams = (tabItem: TabItem) => {
  const { params, path, query } = tabItem;
  return {
    params: params || {},
    path,
    query: query || {},
  };
};

const useTabsStore = defineStore({
  id: "tabs",
  state: (): TabsSate => ({
    cacheTabList: new Set(),
    tabList: [],
    tasMap: {},
    indexRouteName: "",
  }),
  getters: {
    getTabList(): TabItem[] {
      return this.tabList;
    },
    getCacheTabList(): string[] {
      return Array.from(this.cacheTabList);
    },
  },
  actions: {
    setRouteName(name: RouteRecordName) {
      this.indexRouteName = name;
    },
    addCache(componentName?: string) {
      if (componentName) this.cacheTabList.add(componentName);
    },
    removeCache(componentName?: string) {
      if (componentName && this.cacheTabList.has(componentName)) {
        this.cacheTabList.delete(componentName);
      }
    },
    clearCache() {
      this.cacheTabList.clear();
    },
    resetState() {
      this.cacheTabList = new Set();
      this.tabList = [];
      this.tasMap = {};
      this.indexRouteName = "";
    },
    addTab(router: Router) {
      const route = unref(router.currentRoute);
      const { name, query, meta, params, fullPath, path } = route;
      if (isCannotAddRoute(route, router)) return;
      const hasTabIndex = getHasTabIndex(fullPath!, this.tabList);
      const componentName = getComponentName(route);
      const tabItem = {
        name: name!,
        path,
        fullPath,
        title: meta?.title,
        query,
        params,
      };
      this.tasMap[fullPath] = tabItem;
      if (meta?.keepAlive) {
        this.addCache(componentName);
      }
      if (hasTabIndex != -1) {
        return;
      }
      this.tabList.push(tabItem);
    },
    removeTab(fullPath: string, router: Router) {
      const { currentRoute, push } = router;
      const index = findTabsIndex(fullPath, this.tabList);
      // 移除tab
      if (this.tabList.length > 1) {
        index !== -1 && this.tabList.splice(index, 1);
      }
      const componentName = getComponentName(currentRoute.value);
      this.removeCache(componentName);

      if (fullPath !== currentRoute.value.fullPath) {
        return;
      }
      // 删除选中的tab
      let toTab: TabItem | null = null;

      if (index === 0) {
        toTab = this.tabList[index];
      } else {
        toTab = this.tabList[index - 1];
      }

      const toRoute = getRouteParams(toTab);
      push(toRoute);
    },
    removeOtherTab(route: RouteLocationNormalized) {
      this.tabList = this.tabList.filter(
        (item) => item.fullPath == route.fullPath
      );
      const componentName = getComponentName(route);
      this.cacheTabList.forEach((name) => {
        if (componentName !== name) {
          this.removeCache(name);
        }
      });
    },
    removeAllTab(router: Router) {
      const { push, currentRoute } = router;
      const { name } = unref(currentRoute);
      if (name == this.indexRouteName) {
        this.removeOtherTab(currentRoute.value);
        return;
      }
      this.tabList = [];
      this.clearCache();
      push(PageEnum.INDEX);
    },
  },
});

export default useTabsStore;
